// import com.alibaba.druid.DbType;
// import com.alibaba.druid.sql.ast.*;
// import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
// import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr;
// import com.alibaba.druid.sql.visitor.SQLASTVisitor;

// import java.util.ArrayList;
// import java.util.List;

#include "SQLCreateIndexStatement.h"
#include "../../visitor/SQLASTVisitor.h"
#include "../../../utils/instanceof.h"
#include "../../../utils/listTran.h"
#include "SQLExternalRecordFormat.h"
#include "../SQLName.h"
#include "../SQLIndexDefinition.h"
#include "SQLExprTableSource.h"

SQLCreateIndexStatement::SQLCreateIndexStatement()
{
  indexDefinition->setParent(SharedObject(SQLCreateIndexStatement));
  SQLIndexDefinition_ptr indexDefinition = SQLIndexDefinition_ptr(new SQLIndexDefinition());
  SQLAssignItem_list_ptr properties = std::make_shared<std::list<SQLAssignItem_ptr>>();
  SQLAssignItem_list_ptr tableProperties = std::make_shared<std::list<SQLAssignItem_ptr>>();
}

SQLCreateIndexStatement::SQLCreateIndexStatement(DbType_ptr dbType)
    : SQLStatementImpl(dbType)
{
  indexDefinition->setParent(SharedObject(SQLCreateIndexStatement));
  SQLIndexDefinition_ptr indexDefinition = SQLIndexDefinition_ptr(new SQLIndexDefinition());
  SQLAssignItem_list_ptr properties = std::make_shared<std::list<SQLAssignItem_ptr>>();
  SQLAssignItem_list_ptr tableProperties = std::make_shared<std::list<SQLAssignItem_ptr>>();
}

SQLIndexDefinition_ptr SQLCreateIndexStatement::getIndexDefinition()
{
  return indexDefinition;
}

SQLTableSource_ptr SQLCreateIndexStatement::getTable()
{
  return indexDefinition->getTable();
}

void SQLCreateIndexStatement::setTable(SQLName_ptr table)
{
  this->setTable(SQLExprTableSource_ptr(new SQLExprTableSource(table)));
}

void SQLCreateIndexStatement::setTable(SQLTableSource_ptr table)
{
  indexDefinition->setTable(table);
}

string_ptr SQLCreateIndexStatement::getTableName()
{
  if (instanceof <SQLTableSource, SQLExprTableSource>(indexDefinition->getTable()))
  {
    SQLExpr_ptr expr = (std::dynamic_pointer_cast<SQLExprTableSource>(indexDefinition->getTable()))->getExpr();
    if (instanceof <SQLExpr, SQLIdentifierExpr>(expr))
    {
      return (std::dynamic_pointer_cast<SQLIdentifierExpr>(expr))->getName();
    }
    else if (instanceof <SQLExpr, SQLPropertyExpr>(expr))
    {
      return (std::dynamic_pointer_cast<SQLPropertyExpr>(expr))->getName();
    }
  }

  return nullptr;
}

SQLSelectOrderByItem_list_ptr SQLCreateIndexStatement::getItems()
{
  return indexDefinition->getColumns();
}

void SQLCreateIndexStatement::addItem(SQLSelectOrderByItem_ptr item)
{
  if (item != nullptr)
  {
    item->setParent(SharedObject(SQLCreateIndexStatement));
  }
  indexDefinition->getColumns()->push_back(item);
}

SQLName_ptr SQLCreateIndexStatement::getName()
{
  return indexDefinition->getName();
}

void SQLCreateIndexStatement::setName(SQLName_ptr name)
{
  indexDefinition->setName(name);
}

string_ptr SQLCreateIndexStatement::getType()
{
  return indexDefinition->getType();
}

void SQLCreateIndexStatement::setType(string_ptr type)
{
  indexDefinition->setType(type);
}

string_ptr SQLCreateIndexStatement::getUsing()
{
  return indexDefinition->hasOptions() ? indexDefinition->getOptions()->getIndexType() : nullptr;
}

void SQLCreateIndexStatement::setUsing(string_ptr using_)
{
  indexDefinition->getOptions()->setIndexType(using_);
}

// @Override
void SQLCreateIndexStatement::accept0(SQLASTVisitor_ptr visitor)
{
  if (visitor->visit(SharedObject(SQLCreateIndexStatement)))
  {
    acceptChild(visitor, indexDefinition->getName());
    acceptChild(visitor, indexDefinition->getTable());
    SQLObject_list_ptr tmp = ListTran::tran_class<SQLSelectOrderByItem, SQLObject>(indexDefinition->getColumns());
    acceptChild(visitor, tmp);
    acceptChild(visitor, tablespace);
    acceptChild(visitor, in);
  }
  visitor->endVisit(SharedObject(SQLCreateIndexStatement));
}

// @Override
SQLObject_list_ptr SQLCreateIndexStatement::getChildren()
{
  SQLObject_list_ptr children = std::make_shared<std::list<SQLObject_ptr>>();
  if (indexDefinition->getName() != nullptr)
  {
    children->push_back(indexDefinition->getName());
  }

  if (indexDefinition->getTable() != nullptr)
  {
    children->push_back(indexDefinition->getTable());
  }

  // children.addAll(indexDefinition->getColumns());
  for (auto it : *indexDefinition->getColumns())
  {
    children->push_back(it);
  }
  return children;
}

string_ptr SQLCreateIndexStatement::getSchema()
{
  SQLName_ptr name = nullptr;
  if (instanceof <SQLTableSource, SQLExprTableSource>(indexDefinition->getTable()))
  {
    SQLExpr_ptr expr = (std::dynamic_pointer_cast<SQLExprTableSource>(indexDefinition->getTable()))->getExpr();
    if (instanceof <SQLExpr, SQLName>(expr))
    {
      name = std::dynamic_pointer_cast<SQLName>(expr);
    }
  }

  if (name == nullptr)
  {
    return nullptr;
  }

  if (instanceof <SQLName, SQLPropertyExpr>(name))
  {
    return (std::dynamic_pointer_cast<SQLPropertyExpr>(name))->getOwnernName();
  }

  return nullptr;
}

SQLObject_ptr SQLCreateIndexStatement::clone()
{
  SQLObject_ptr clone_tmp = SQLCreateIndexStatement_ptr(new SQLCreateIndexStatement());
  SQLCreateIndexStatement_ptr x = std::dynamic_pointer_cast<SQLCreateIndexStatement>(clone_tmp);
  // SQLCreateIndexStatement x = new SQLCreateIndexStatement();
  indexDefinition->cloneTo(x->indexDefinition);
  x->setIfNotExists(ifNotExists);
  return x;
}

SQLExpr_ptr SQLCreateIndexStatement::getComment()
{
  return indexDefinition->hasOptions() ? indexDefinition->getOptions()->getComment() : nullptr;
}

void SQLCreateIndexStatement::setComment(SQLExpr_ptr x)
{
  indexDefinition->getOptions()->setComment(x);
}

SQLName_ptr SQLCreateIndexStatement::getTablespace()
{
  return tablespace;
}

void SQLCreateIndexStatement::setTablespace(SQLName_ptr x)
{
  if (x != nullptr)
  {
    x->setParent(SharedObject(SQLCreateIndexStatement));
  }
  this->tablespace = x;
}

BOOL_ptr SQLCreateIndexStatement::isConcurrently()
{
  return concurrently;
}

void SQLCreateIndexStatement::setConcurrently(BOOL_ptr concurrently)
{
  this->concurrently = concurrently;
}

SQLAssignItem_list_ptr SQLCreateIndexStatement::getOptions()
{
  return indexDefinition->getCompatibleOptions();
}

BOOL_ptr SQLCreateIndexStatement::isDeferedRebuild()
{
  return deferedRebuild;
}

void SQLCreateIndexStatement::setDeferedRebuild(BOOL_ptr deferedRebuild)
{
  this->deferedRebuild = deferedRebuild;
}

SQLTableSource_ptr SQLCreateIndexStatement::getIn()
{
  return in;
}

void SQLCreateIndexStatement::setIn(SQLName_ptr x)
{
  if (x == nullptr)
  {
    this->in = nullptr;
    return;
  }
  setIn(SQLExprTableSource_ptr(new SQLExprTableSource(x)));
}

void SQLCreateIndexStatement::setIn(SQLTableSource_ptr x)
{
  if (x != nullptr)
  {
    x->setParent(SharedObject(SQLCreateIndexStatement));
  }
  this->in = x;
}

SQLName_ptr SQLCreateIndexStatement::getStoredAs()
{
  return storedAs;
}

void SQLCreateIndexStatement::setStoredAs(SQLName_ptr x)
{
  if (x != nullptr)
  {
    x->setParent(SharedObject(SQLCreateIndexStatement));
  }
  this->storedAs = x;
}

SQLExternalRecordFormat_ptr SQLCreateIndexStatement::getRowFormat()
{
  return rowFormat;
}

void SQLCreateIndexStatement::setRowFormat(SQLExternalRecordFormat_ptr x)
{
  if (x != nullptr)
  {
    x->setParent(SharedObject(SQLCreateIndexStatement));
  }
  this->rowFormat = x;
}

SQLAssignItem_list_ptr SQLCreateIndexStatement::getProperties()
{
  return properties;
}

SQLAssignItem_list_ptr SQLCreateIndexStatement::getTableProperties()
{
  return tableProperties;
}

void SQLCreateIndexStatement::addOption(string_ptr name, SQLExpr_ptr value)
{
  SQLAssignItem_ptr assignItem = SQLAssignItem_ptr(new SQLAssignItem(SQLIdentifierExpr_ptr(new SQLIdentifierExpr(name)), value));
  assignItem->setParent(SharedObject(SQLCreateIndexStatement));
  // Add both with same object.
  indexDefinition->getOptions()->getOtherOptions()->push_back(assignItem);
  indexDefinition->getCompatibleOptions()->push_back(assignItem);
}

BOOL_ptr SQLCreateIndexStatement::isGlobal()
{
  return indexDefinition->isGlobal();
}

void SQLCreateIndexStatement::setGlobal(BOOL_ptr global)
{
  indexDefinition->setGlobal(global);
}

BOOL_ptr SQLCreateIndexStatement::isLocal()
{
  return indexDefinition->isLocal();
}

void SQLCreateIndexStatement::setLocal(BOOL_ptr local)
{
  indexDefinition->setLocal(local);
}

SQLExpr_ptr SQLCreateIndexStatement::getDbPartitionBy()
{
  return indexDefinition->getDbPartitionBy();
}

void SQLCreateIndexStatement::setDbPartitionBy(SQLExpr_ptr x)
{
  indexDefinition->setDbPartitionBy(x);
}

SQLExpr_ptr SQLCreateIndexStatement::getTablePartitions()
{
  return indexDefinition->getTbPartitions();
}

void SQLCreateIndexStatement::setTablePartitions(SQLExpr_ptr x)
{
  indexDefinition->setTbPartitions(x);
}

SQLExpr_ptr SQLCreateIndexStatement::getTablePartitionBy()
{
  return indexDefinition->getTbPartitionBy();
}

void SQLCreateIndexStatement::setTablePartitionBy(SQLExpr_ptr x)
{
  indexDefinition->setTbPartitionBy(x);
}

BOOL_ptr SQLCreateIndexStatement::isStoring()
{
  return storing;
}

void SQLCreateIndexStatement::setStoring(BOOL_ptr storing)
{
  this->storing = storing;
}

// @Override
SQLName_list_ptr SQLCreateIndexStatement::getCovering()
{
  return indexDefinition->getCovering();
}

// @Override
SQLSelectOrderByItem_list_ptr SQLCreateIndexStatement::getColumns()
{
  return indexDefinition->getColumns();
}

BOOL_ptr SQLCreateIndexStatement::isIfNotExists()
{
  return ifNotExists;
}

void SQLCreateIndexStatement::setIfNotExists(BOOL_ptr ifNotExists)
{
  this->ifNotExists = ifNotExists;
}

// @Override
SQLDDLStatement::DDLObjectType SQLCreateIndexStatement::getDDLObjectType()
{
  return SQLDDLStatement::DDLObjectType::INDEX;
}
